# Snow CLI Usage Documentation - Privacy Settings Guide

Privacy Settings let Snow CLI send selected tool result content to a local privacy filter API for redaction before the content is passed to the model. This is useful when code, logs, terminal output, file content, or search results may contain personally identifiable information such as names, email addresses, phone numbers, or similar sensitive text.

## Feature Overview

Snow CLI's privacy filter currently focuses on tool result content:

- Tool results such as file reads, code search results, and terminal output can be redacted according to your configuration.
- The redaction service is self-hosted by the user. Snow CLI only calls the HTTP API you configure.
- Both project-level and global settings are supported. Project-level settings take precedence over global settings.
- You can select which tools should have their results redacted.
- If the privacy filter API is unavailable, returns an unexpected response, or has no URL configured, Snow CLI keeps the original content and continues working.

The recommended local deployment project is:

```text
https://github.com/MayDay-wpf/privacy-filter-api
```

This project uses Hugging Face Transformers.js to load OpenAI's `openai/privacy-filter` ONNX model locally. It provides local PII detection and text masking APIs without sending the text to a remote inference service.

## privacy-filter-api Findings

`privacy-filter-api` is a local HTTP API service. Its main capabilities are:

| Capability | Description |
| --- | --- |
| Local model | Uses `openai/privacy-filter` and loads local ONNX model files through Transformers.js. |
| PII detection | `POST /detect` returns detected entities, including `label`, `score`, `text`, `start`, and `end`. |
| Text masking | `POST /mask` returns `masked_text`; `mask_token` controls the placeholder format. |
| Health check | `GET /health` returns service status, model name, whether the model has been loaded, and auth status. |
| API docs | `/docs` provides Swagger UI, and `/openapi.json` provides the OpenAPI JSON. |
| Authentication | Supports the `x-api-key` header and `Authorization: Bearer <API_KEY>`. |
| Deployment | Supports npm startup, PM2 daemon mode, and Docker deployment. |
| Model precision | Supports downloading precision variants such as `fp32`, `fp16`, `q4`, `q4f16`, and `quantized`. |

When Snow CLI calls the masking API, it sends a request like:

```json
{
  "text": "text to redact",
  "aggregation_strategy": "simple",
  "mask_token": "[{label}]"
}
```

The expected response is:

```json
{
  "model": "openai/privacy-filter",
  "masked_text": "redacted text",
  "entities": []
}
```

Therefore, the URL configured in Snow CLI should be the full `/mask` endpoint, for example:

```text
http://127.0.0.1:3000/mask
```

## Quick Deploy the Privacy Filter API

### Requirements

The deployment machine needs:

- Git
- Node.js 20 or later
- npm
- Python 3, only required for the initial Hugging Face model download

### One-command Installation with PM2 Daemon

Run from any directory:

```bash
git clone https://github.com/MayDay-wpf/privacy-filter-api.git privacy-filter-api
cd privacy-filter-api
npm install
npm run install:daemon
```

The script installs dependencies, checks the local model, asks which model precision to download if needed, and starts `privacy-filter-api` with PM2.

Common options:

```bash
npm run install:daemon -- --precision fp16
npm run install:daemon -- --dir /opt/privacy-filter-api --precision fp16
npm run install:daemon -- --yes
npm run install:daemon -- --no-startup
```

For first-time use, `fp16` is recommended because it usually provides a good balance between size and speed. Use `fp32` if you prioritize precision, or try `q4` / `q4f16` if resources are limited.

After installation, check the service with:

```bash
pm2 status
pm2 logs privacy-filter-api
pm2 restart privacy-filter-api
```

### Manually Download the Model and Start

If you want to control model precision manually, run:

```bash
git clone https://github.com/MayDay-wpf/privacy-filter-api.git privacy-filter-api
cd privacy-filter-api
npm install
npm run download:model -- fp16
npm run start:model -- fp16
```

By default, the service listens on:

```text
http://127.0.0.1:3000
```

Health check:

```bash
curl http://127.0.0.1:3000/health
```

The model is loaded lazily on the first `/detect` or `/mask` request, so `loaded:false` in the health check is normal before the first inference request.

### Configure API Key

Copy the sample environment file:

```bash
cp .env.example .env
```

It is recommended to set an API key:

```env
API_KEY=your-secret-key
API_KEY_HEADER=x-api-key
TRANSFORMERS_DTYPE=fp16
LOCAL_FILES_ONLY=true
```

After this, `/detect` and `/mask` require an API key. `/health`, `/docs`, and `/openapi.json` remain public.

Snow CLI sends both of the following headers:

```text
x-api-key: your-secret-key
Authorization: Bearer your-secret-key
```

So you only need to enter the same API key in Snow CLI Privacy Settings.

## Configure Privacy Settings in Snow CLI

### Open the Settings Page

1. Start Snow CLI.
2. Select `Privacy Settings` on the welcome screen.
3. Choose the configuration location, enable the privacy filter, fill in API settings, and select which tool results should be redacted.

### Configuration Location

Privacy Settings support two locations:

| Location | Description |
| --- | --- |
| Project settings | Saved in the current project's settings and only applies to the current working directory. Use this when you only want protection for a specific project. |
| Global settings | Saved in user-level settings and applies to directories without project-level overrides. Use this when all projects share the same local privacy filter service. |

Project settings have higher priority than global settings. If the current project defines `privacy.enabled`, API URL, or the tool list, Snow CLI uses the project value first; missing fields fall back to global settings.

### Enable Privacy Filter

Toggle the `Enable Privacy Filter` item:

- `Enabled`: tool results enter the privacy filtering flow according to the remaining settings.
- `Disabled`: Snow CLI does not call the privacy filter API, and tool results remain unchanged.

Note: even when enabled, a valid API URL is still required before redaction can happen.

### API Configuration

Open `API Config` and fill in:

| Field | Example | Description |
| --- | --- | --- |
| URL | `http://127.0.0.1:3000/mask` | Required. Use the full `/mask` endpoint. |
| API Key | `your-secret-key` | Optional. Required if the service has `API_KEY` configured. |
| Model | `openai/privacy-filter` | Model name. The default is `openai/privacy-filter`. It is mainly used for recording and UI display at the moment. |

Recommended configuration:

```text
URL: http://127.0.0.1:3000/mask
API Key: your-secret-key
Model: openai/privacy-filter
```

### Tool Result Detection Configuration

Open `Tool Results Config` to select which tools should have their returned content redacted.

The default enabled tools are:

```text
filesystem-read
ace-search
terminal-execute
```

Common recommendations:

- `filesystem-read`: recommended. File content may include names, email addresses, tokens, paths, or customer data.
- `ace-search`: recommended. Search results may include source snippets or sensitive information in comments.
- `terminal-execute`: recommended. Command output may include environment variables, logs, usernames, paths, or API responses.
- `websearch-*`: enable as needed. Public web content usually does not need redaction, but enable it if search results may include user-provided sensitive text.
- MCP tools: decide based on business context. Enable redaction for MCP tools that return customer data, tickets, or database query results.

## Test the Masking Service

Use curl to verify the service first:

```bash
curl -X POST http://127.0.0.1:3000/mask \
  -H 'content-type: application/json' \
  -H 'x-api-key: your-secret-key' \
  -d '{"text":"My name is Harry Potter and my email is harry.potter@hogwarts.edu.","mask_token":"[{label}]"}'
```

Example successful response:

```json
{
  "model": "openai/privacy-filter",
  "masked_text": "My name is [private_person] and my email is [private_email].",
  "entities": [
    {
      "label": "private_person",
      "score": 0.9999,
      "text": " Harry Potter",
      "start": 10,
      "end": 23
    },
    {
      "label": "private_email",
      "score": 0.9999,
      "text": " harry.potter@hogwarts.edu",
      "start": 40,
      "end": 67
    }
  ]
}
```

If curl succeeds, enter the same `/mask` URL and API key in Snow CLI.

## Docker Deployment Example

Build the image:

```bash
docker build -t privacy-filter-api .
```

Run the container and mount the local model directory:

```bash
docker run --rm \
  -p 3000:3000 \
  -e API_KEY=your-secret-key \
  -e TRANSFORMERS_DTYPE=fp16 \
  -e LOCAL_FILES_ONLY=true \
  -v "$PWD/models:/app/models" \
  -v "$PWD/.cache:/app/.cache" \
  privacy-filter-api
```

If the model was downloaded into the image during build, you can omit the `models` mount.

## Troubleshooting

### Snow CLI Does Not Redact Anything

Check:

1. Whether `Enable Privacy Filter` is set to Enabled.
2. Whether the API URL is the full `/mask` endpoint, not just the service root.
3. Whether the current tool is selected in `Tool Results Config`.
4. Whether project-level settings override global settings.
5. Whether the API key matches the `API_KEY` in the service `.env` file.

### Health Check Works, but the First Masking Request Is Slow

This is normal. `privacy-filter-api` loads the model on the first `/detect` or `/mask` request, so the first request is slower than later requests.

### 401 Unauthorized

The service has API key authentication enabled, but the API key in Snow CLI is missing or incorrect. Confirm:

```env
API_KEY=your-secret-key
API_KEY_HEADER=x-api-key
```

Then enter the same `your-secret-key` in Snow CLI `API Config`.

### Original Content Is Returned Unchanged

Possible causes:

- The model did not detect any PII in the text.
- The privacy filter API request failed, and Snow CLI preserved the original content to avoid interrupting the workflow.
- The URL is incorrect and does not point to `/mask`.
- The model precision or local model files do not match `TRANSFORMERS_DTYPE`.

### Production Recommendations

- Deploy the service on localhost or a trusted internal network whenever possible.
- Set `API_KEY`; do not expose an unauthenticated service to the public internet.
- Keep `LOCAL_FILES_ONLY=true` to avoid runtime remote model downloads.
- Use a firewall or reverse proxy to restrict access sources.
- For highly sensitive projects, prefer project-level settings and explicitly select which tools require redaction.
